﻿/*
 * 
 * 
 * 参考网页： https://docs.microsoft.com/zh-cn/dotnet/csharp/whats-new/csharp-8
 * 
 * 
*/

namespace CSharpNewFeatures;

public class CsharpDemo8 : CsharpDemoBase
{
    public override void Run()
    {
        // 01.Readonly 成员
        Console.WriteLine("Readonly 成员的作用是用于定义函数的只读属性，比如以下函数无法修改成员数据。");
        Console.WriteLine("public readonly double Distance => Math.Sqrt(X * X + Y * Y);");

        // 02.默认接口方法
        Console.WriteLine("现在接口可以以类似虚函数的方式实现函数的初始化。");

        // 03.模式匹配增强功能：
        // 04.Switch 表达式
        KeyValuePair kv = new KeyValuePair()
        {
            Key = Random.Shared.Next(0, 100).ToString(),
            Value = Random.Shared.Next(0, 100).ToString(),
        };

        var value = kv switch
        {
            { Key: "0" } => Random.Shared.Next(0, 100).ToString(),
            { Value: "1" } => Random.Shared.Next(0, 100).ToString(),
            _ => "",
        };
        Console.WriteLine(value);

        // 05.属性模式
        // 06.元组模式
        // 07.位置模式
        demo03_07_pattern_match_enhancement();

        // 08.Using 声明
        Console.WriteLine("可以直接使用 using var file = new System.IO.StreamWriter(filepath); 而不需要加大括号，省略了推断过程");

        // 09.静态本地函数
        Console.WriteLine("通过static修饰，避免对变量的修改： static int Add(int left, int right) => left + right;");

        // 10.可处置的 ref 结构 (略)

        // 12.可为空引用类型
        test12_null_warning();

        // 13.异步流 (略)
        // 14.异步可释放 (略)

        // 15.索引和范围
        test15_range_index();

        // 16.Null 合并赋值
        Console.WriteLine("?? 用法:   a == null ? b : b;  --> a ?? v");
        Console.WriteLine("??=用法:  if(a == null) a = v; --> a ??= v");

        // 17.非托管构造类型 (略)

        // 18.嵌套表达式中的 Stackalloc (略)

        // 19.内插逐字字符串的增强功能 (略)
        Console.WriteLine("添加对 @$ 的支持，以前只能$@。");
        // 内插逐字字符串中 $ 和 @ 标记的顺序可以任意安排：$@"..." 和 @$"..." 均为有效的内插逐字字符串。 在早期 C# 版本中，$ 标记必须出现在 @ 标记之前。
    }

    class KeyValuePair
    {
        public string Key { set; get; } = "nokey";
        public string? Value { get; set; }
        public override string ToString()
        {
            return $"({Key}, {Value})";
        }
    }

    private void test12_null_warning()
    {
        Console.WriteLine("如果一个变量可能为null，则需要在定义时加上问号，如： string? s = null; ");
        // Null-coalescing assignment
        // C# 8.0 introduces the null-coalescing assignment operator ??=.
        // You can use the ??= operator to assign the value of its right-hand operand
        // to its left-hand operand only if the left-hand operand evaluates to null.
        List<int>? numbers = null;
        int? i = null;

        numbers ??= new List<int>();
        numbers.Add(i ??= 17);
        numbers.Add(i ??= 20);

        Console.WriteLine(string.Join(" ", numbers));  // output: 17 17
        Console.WriteLine(i);  // output: 17
    }

    private object demo03_07_pattern_match_enhancement(int type = 0)
    {
        Rainbow colorBand = Rainbow.Red;
        Address location = new Address() { State = "WA" };
        decimal salePrice = 0.5M;
        HandPattern first = HandPattern.Rock;
        HandPattern second = HandPattern.Paper;
        Point p = new Point(3, 5);
        if (type == 0)
        {
            var res = colorBand switch
            {
                Rainbow.Red => new RGBColor(0xFF, 0x00, 0x00),
                Rainbow.Orange => new RGBColor(0xFF, 0x7F, 0x00),
                Rainbow.Yellow => new RGBColor(0xFF, 0xFF, 0x00),
                Rainbow.Green => new RGBColor(0x00, 0xFF, 0x00),
                Rainbow.Blue => new RGBColor(0x00, 0x00, 0xFF),
                Rainbow.Indigo => new RGBColor(0x4B, 0x00, 0x82),
                Rainbow.Violet => new RGBColor(0x94, 0x00, 0xD3),
                _ => throw new ArgumentException(message: "invalid enum value", paramName: nameof(colorBand)),
            };

            return res;
        }
        else if (type == 2)
        {
            return location switch
            {
                { State: "WA" } => salePrice * 0.06M,
                { State: "MN" } => salePrice * 0.075M,
                { State: "MI" } => salePrice * 0.05M,
                // other cases removed for brevity...
                _ => 0M
            };
        }
        else if (type == 3)
        {
            return (first, second) switch
            {
                (HandPattern.Rock, HandPattern.Paper) => "rock is covered by paper. Paper wins.",
                (HandPattern.Paper, HandPattern.Rock) => "paper covers rock. Paper wins.",
                (HandPattern.Rock, HandPattern.Scissors) => "rock breaks scissors. Rock wins.",
                (HandPattern.Scissors, HandPattern.Rock) => "scissors is broken by rock. Rock wins.",
                (HandPattern.Paper, HandPattern.Scissors) => "paper is cut by scissors. Scissors wins.",
                (HandPattern.Scissors, HandPattern.Paper) => "scissors cuts paper. Scissors wins.",
                (_, _) => "tie"
            };
        }
        else if (type == 4)
        {
            return p switch
            {
                (0, 0) => Quadrant.Origin,
                var (x, y) when x > 0 && y > 0 => Quadrant.One,
                var (x, y) when x < 0 && y > 0 => Quadrant.Two,
                var (x, y) when x < 0 && y < 0 => Quadrant.Three,
                var (x, y) when x > 0 && y < 0 => Quadrant.Four,
                var (_, _) => Quadrant.OnBorder,
                _ => Quadrant.Unknown
            };
        }

        object o = p;
        object o1 = o switch
        {
            Point point => p.X,
            Quadrant quadrant => quadrant,
            _ => 0
        };

        return o1;
    }

    public void test0()
    {
        printTitle("0 Readonly members");
        // 用于加在结构体的方法前，保证成员变量不会被修改，如：
        // public readonly double Distance => Math.Sqrt(X * X + Y * Y);

        // 以下代码编译时会出错
        // public readonly void Translate(int xOffset, int yOffset){
        //    X += xOffset;
        //    Y += yOffset;
        // } 
    }

    public enum Rainbow
    {
        Red,
        Orange,
        Yellow,
        Green,
        Blue,
        Indigo,
        Violet
    }

    public struct RGBColor
    {
        public byte r, g, b;
        public RGBColor(byte r, byte g, byte b) { this.r = r; this.g = g; this.b = b; }
        public override string ToString() => $"({r}, {g}, {b})";
    }

    public static RGBColor FromRainbow(Rainbow colorBand) =>
        colorBand switch
        {
            Rainbow.Red => new RGBColor(0xFF, 0x00, 0x00),
            Rainbow.Orange => new RGBColor(0xFF, 0x7F, 0x00),
            Rainbow.Yellow => new RGBColor(0xFF, 0xFF, 0x00),
            Rainbow.Green => new RGBColor(0x00, 0xFF, 0x00),
            Rainbow.Blue => new RGBColor(0x00, 0x00, 0xFF),
            Rainbow.Indigo => new RGBColor(0x4B, 0x00, 0x82),
            Rainbow.Violet => new RGBColor(0x94, 0x00, 0xD3),
            _ => throw new ArgumentException(message: "invalid enum value", paramName: nameof(colorBand)),
        };


    public static decimal ComputeSalesTax(Address location, decimal salePrice) =>
    location switch
    {
        { State: "WA" } => salePrice * 0.06M,
        { State: "MN" } => salePrice * 0.075M,
        { State: "MI" } => salePrice * 0.05M,
        // other cases removed for brevity...
        _ => 0M
    };




    public static string RockPaperScissors(string first, string second)
    => (first, second) switch
    {
        ("rock", "paper") => "rock is covered by paper. Paper wins.",
        ("rock", "scissors") => "rock breaks scissors. Rock wins.",
        ("paper", "rock") => "paper covers rock. Paper wins.",
        ("paper", "scissors") => "paper is cut by scissors. Scissors wins.",
        ("scissors", "rock") => "scissors is broken by rock. Rock wins.",
        ("scissors", "paper") => "scissors cuts paper. Scissors wins.",
        (_, _) => "tie"
    };


    public static string RockPaperScissors(HandPattern first, HandPattern second)
        => (first, second) switch
        {
            (HandPattern.Rock, HandPattern.Paper) => "rock is covered by paper. Paper wins.",
            (HandPattern.Paper, HandPattern.Rock) => "paper covers rock. Paper wins.",
            (HandPattern.Rock, HandPattern.Scissors) => "rock breaks scissors. Rock wins.",
            (HandPattern.Scissors, HandPattern.Rock) => "scissors is broken by rock. Rock wins.",
            (HandPattern.Paper, HandPattern.Scissors) => "paper is cut by scissors. Scissors wins.",
            (HandPattern.Scissors, HandPattern.Paper) => "scissors cuts paper. Scissors wins.",
            (_, _) => "tie"
        };


    static Quadrant GetQuadrant(Point point) =>
        point switch
        {
            (0, 0) => Quadrant.Origin,
            var (x, y) when x > 0 && y > 0 => Quadrant.One,
            var (x, y) when x < 0 && y > 0 => Quadrant.Two,
            var (x, y) when x < 0 && y < 0 => Quadrant.Three,
            var (x, y) when x > 0 && y < 0 => Quadrant.Four,
            var (_, _) => Quadrant.OnBorder,
            _ => Quadrant.Unknown
        };


    public void test15_range_index()
    {
        printTitle("Switch expressions");
        foreach (Rainbow item in Enum.GetValues(typeof(Rainbow)))
            Console.WriteLine(FromRainbow(item));

        printTitle("Property patterns");
        Address location = new Address() { State = "MI" };
        Console.WriteLine("Final Price: " + ComputeSalesTax(location, 100));

        // Using declarations
        // 可以直接这样写，file在范围尾会自动被销毁
        // using var file = new System.IO.StreamWriter("WriteLines2.txt");

        // Static local functions, 保证不对内部变量进行引用修改
        var v1 = AStaticLocalFunction();
        var v2 = AStaticLocalFunction();
        Console.WriteLine("v1 =" + v1);
        Console.WriteLine("v2 =" + v2);

        // Asynchronous streams


        // Indices and ranges
        var words = new string[]
        {
                        // index from start    index from end
            "The",      // 0                   ^9
            "quick",    // 1                   ^8
            "brown",    // 2                   ^7
            "fox",      // 3                   ^6
            "jumped",   // 4                   ^5
            "over",     // 5                   ^4
            "the",      // 6                   ^3
            "lazy",     // 7                   ^2
            "dog"       // 8                   ^1
        };              // 9 (or words.Length) ^0

        Console.WriteLine($"The last word is {words[^1]}");
        var quickBrownFox = words[1..4];
        var lazyDog = words[^2..^0];
        var allWords = words[..]; // contains "The" through "dog".
        var firstPhrase = words[..4]; // contains "The" through "fox"
        var lastPhrase = words[6..]; // contains "the", "lazy" and "dog"
        Range phrase = 1..4;
        var text = words[phrase];
    }

    int M()
    {
        int y;
        LocalFunction();
        return y;

        void LocalFunction() => y = 0;
    }

    int AStaticLocalFunction()
    {
        int y = 5;
        int x = 7;
        return Add(x, y);

        static int Add(int left, int right) => left + right;
    }

}

public class Address { public string? State = null; }

public enum HandPattern { Rock, Paper, Scissors }

public enum Quadrant
{
    Unknown,
    Origin,
    One,
    Two,
    Three,
    Four,
    OnBorder
}

public class Point
{
    public int X { get; }
    public int Y { get; }

    public Point(int x, int y) => (X, Y) = (x, y);

    public void Deconstruct(out int x, out int y) => (x, y) = (X, Y);
}